
/*******************************************************************************
 * The code below this comment is integral part of the project "Jelliphy".
 * 
 * "Jelliphy" is a project created by: 
 * Dispage - Patrizio Gelosi
 * Via A. De Gasperi 91 
 * P. Potenza Picena (MC) - Italy
 * 
 * (Hereby referred to as "DISPAGE")
 * 
 * Copyright (c) 2011 DISPAGE.
 * 
 * @Released on: 02-06-2011
 * @Version: 1.0.00
 * @Build: 1109
 * @Site: http://www.dispage.com
 * @Contacts: http://www.dispage.com/contacts
 * 
 * The contents of this file are released under the GNU General Public License
 * version 3 as published by the Free Software Foundation that can be found at
 * the address "http://opensource.org/licenses/gpl-3.0.html". If the license
 * cannot be found, write to the Free Software Foundation, Inc., 51 Franklin
 * Street, Fifth Floor, Boston, MA 02110-1301 USA.
 * 
 * You may not use the present file except in compliance with the License.
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the License
 * for the specific language governing rights and limitations under the
 * License.
 * 
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU General Public License version 3.
 * 
 * In accordance with Section 7(b) of the GNU General Public License version 3,
 * these Appropriate Legal Notices must retain the display of the "Powered by
 * Dispage" logo. If the display of the logo is not reasonably feasible for
 * technical reasons, the Appropriate Legal Notices must display the words
 * "Powered by Dispage".
 * 
 ******************************************************************************/

var MGCR = new function () {

	var that = this,
		$canvas,

		ruleFuncs = ['deleteRule', 'deleteCSS'],
	
		excludedCss = [
			'mg-melt.css',
			'mg-melt.min.css',
			'jquery-ui.custom.css',
			'ui.jqgrid.css',
			'jPicker.min.css'
		],

		sheetMap = [],
		ruleActionMap = {
			'editRule'		: 'edit-rule', 
			'addCSS'		: 'add-css-rule', 
			'editCSS'		: 'edit-css-rule', 
			'deleteCSS'		: 'delete-css-rule'
		},

		curRule, curSheet, curRules,
		ruleProperty,
		lastCharRep,
		CSSOutdated = false,
		
		f,
		propList = [],
		

		populateSelector = function () {

			var res = '<option value="All">All</option>',
				selected = false;

			JlQ.rule.sheets().each(function (i, v) {
				var filename = v.href ? v.href.replace(/^.*\//, '').replace(/\?.*$/, '') : '';
				
				try {
					if (!filename || JlQ.inArray(filename, excludedCss) != -1 || !v[ruleProperty]) return true;
				} catch (e) {}

				sheetMap[v.href] = i;

				res += '<option value="' + i + '" ';
				if (!selected) {
					res += ' selected';
					selected = true;
				}
				res += '>' + filename + '</option>';
			});
			JlQ('#mg-cur-sheet').html(res);
		},

		filterLocalPath = function (str) {

			var rxHttp = /^(https?:\/\/)/,
				locHref = document.location.href.replace(rxHttp, '').replace(/[?&#].*$/, ''),
				ls = locHref.split('/'),
				i, l, rx;
			
			str = str.replace(rxHttp, '');

			for (i = 0; l = ls[i]; i++) {
				rx = new RegExp('^' + l + '\\/');
				if (str.search(rx) != -1) {
					str = str.replace(rx, '');
				}
				else {
					break;
				}	
			}
			return str;
		},
			
		getRuleInd = function ($el, rule) {

			var txt = $el.data('oval') || $el.text(),
				ind;

			if (JlQ.browser.opera) {
				txt = txt.replace(/;}$/, '}');
			}
			if (rule.length > 1) {
				rule.each(function (i) {
					if (this.cssText == txt) {
						ind = i;
						return false;
					}
				});
				return ind;
			}
			else {
				return 0;
			}
		},
			
		assignSheet = function () {

			curRule = JlQ('#mg-cur-sheet').val();
			
			try {
				if (curRule == 'All') {
					curSheet = JlQ.rule.sheets();
					curRules = curSheet.cssRules();
				}
				else {
					curSheet = JlQ.rule.sheets()[curRule];
					curRules = curSheet[ruleProperty];
				}
			}
			catch (e) {
				$canvas.html('<div class="mg-css-message">CSS rules not available for this stylesheet.</div>');
				return false;
			}
			return true;
		},

		editRuleKeypress = function(event) {

			switch (event.keyCode) {
				case 13:
					saveRule();
					break;
				case 27:
					cancelRule();
					break;
			}
		},

		saveRule = function () {

			var $el = JlQ('#mg-input-rule'),
				$parent = $el.parent(),
				action = $parent.parent().attr('id') == 'mg-add-css-element' ? 'addRule' : 'editRule',
				val = $el.val();

			if (!$el.length) return;

			if (action == 'addRule' && val.search(/\w|\*/) == -1) {
				MGDial.warning(MGLang.warnings.empty_new_rule);
				return;
			}
			$el.siblings('.mg-images').remove();

			$el.replaceWith('<span>' + val + '</span>');

			operRule.call($parent.children('span').get(0), action);
		},

		cancelRule = function () {

			var $el = JlQ('#mg-input-rule'),
				$granpa;
				
			cancelNewCSS();

			if (!$el.length) return;

			$granpa = $el.parent().parent();

			if ($granpa.attr('id') == 'mg-add-css-element') {
				$granpa.remove();
			}
			else {
				$el.siblings('.mg-images').remove();
				$el.replaceWith('<span>' + $el.data('oval') + '</span>');
			}
		},

		saveNewCSS = function () {

			var newProp = JlQ('#mg-add-rule-name').val(),
				newVal = JlQ('.mg-changeable-input', $canvas).val(),
				$newMask = JlQ('.mg-add-rule'),
				$p = $newMask.parent().siblings('p');

			$newMask.replaceWith('<div>' + newProp + ':<font> ' + newVal + ';</font>');

			operRule.call($p.children('span').get(0), 'addCSS');
		},

		cancelNewCSS = function () {

			JlQ('.mg-add-rule').remove();
		},

		selectCSSName = function (event, ui) {

			var $inputValue = JlQ('.mg-changeable-input', $canvas);

			if (!ui || typeof(ui.item) == 'undefined') return;

			JlQ('.mg-panel-jpicker, .mg-panel-filemanage, .mg-panel-shadow').addClass('mg-hidden');

			$inputValue.attr('id', 'mg-elproperty-' + ui.item.value);

			MGED.editProperty.call($inputValue.parent(), event);

			JlQ('.mg-property-input', $canvas).addClass('mg-changeable-input');
		},

		addRule = function (ev) {

			var $elemAfter = JlQ(this).parent().nextUntil('.mg-sheettxt'),
				$addAfter = $elemAfter.last(),
				$container = JlQ('#mg-csscanv-container'),
				$newEl;

			if (JlQ.browser.msie) {
				MGDial.warning(MGLang.warnings.new_rule_denied_for_ie);
				return;
			}

			$addAfter.after('<div id="mg-add-css-element" class="mg-csstxt"><p ruleind="'+$elemAfter.length+'"><span></span> {</p><div class="mg-cssr"></div>}</div>');

			$newEl = JlQ('#mg-add-css-element');

			editRule.call($newEl.children('p').get(0), ev);

			$container.scrollTop($newEl.position().top - $container.height() / 2 + $container.scrollTop());
		},

		editRule = function (ev) {

			var $el = JlQ(this).children('span'),
				$granpa = $el.parent().parent(),
				otxt = $el.text(),
				$oel = JlQ('#mg-input-rule', $canvas);

			if ($oel.length) {
				if (JlQ.contains(this, $oel.get(0))) {
					$oel.focus();
					return;
				}
				else {
					cancelRule();
				}
			}
			if (JlQ('input.mg-property-input', $canvas).length) {
				MGED.cancelProperty();
			}
			$granpa.data({
				'oval' : $granpa.text(),
				'osel' : otxt
			});

			JlQ('#mg-delete-element, #mg-add-csselement').remove();

			JlQ('<input id="mg-input-rule" type="text" class="mg-input" style="max-width:'+$canvas.width()+'px;" size="' + (otxt.length +5) + '" value=\'' + MGUtils.text2SQString(otxt) + '\' />')
				.data('oval', otxt)
				.click(function (ev) {ev.stopPropagation()})
				.keypress(editRuleKeypress)
				.replaceAll($el);

			MGED.addEditIcons(this, {save: saveRule, cancel: cancelRule});

			JlQ('#mg-input-rule', $canvas).focus();

			ev.stopPropagation();
		},

		addCSS = function (ev) {

			var $cssDiv = JlQ(this).parent().siblings('.mg-cssr'),
				$cssText = $cssDiv.parent(),
				maxw = $canvas.width() / 2 - 10;

			$cssText.data('oval', $cssText.text());
			$cssDiv.append('<div class="mg-add-rule"><input id="mg-add-rule-name" type="text" class="mg-input" style="max-width:'+maxw+'px;" size="30"/> : <input id="mg-elproperty-" class="mg-input mg-changeable-input" type="text" /></div>');

			JlQ('.mg-changeable-input', $canvas).width($cssDiv.width() - JlQ('#mg-add-rule-name').width() -20);

			JlQ('#mg-add-rule-name').autocomplete({
					minLength: 0,
					select: selectCSSName,
					open: MGED.openAutocomplete,
					source: function (req, responseFn) {
						var re = JlQ.ui.autocomplete.escapeRegex(req.term),
							matcher = new RegExp("^" + re, "i" );
							a = JlQ.grep(propList, function (item,index){
								return matcher.test(item);
							});
						responseFn(a);
					}
				})
				.click(MGED.clickAutocomplete)
				.focus();

			MGED.addEditIcons($cssDiv.children('.mg-add-rule').get(0), {save: saveNewCSS, cancel: cancelNewCSS});

			JlQ('.JLui-autocomplete').addClass('mg-nohighlight');

			ev.stopPropagation();
		},

		editCSS = function (ev) {

			var $this = JlQ(this),
				$rule, elms;

			if (JlQ('input', $this).length) return;

			elms = $this.text().match(/([^:\s*]+)\s*:\s*([^;}]*?)\s*;/);

			cancelRule();

			$rule = $this.closest('.mg-csstxt');
			$rule.data('oval', $rule.text());

			$this.data('rval', elms[2])
				.html('<span>'+elms[1]+'</span><font id="mg-elproperty-'+elms[1]+'" class="mg-changeable-input">'+ elms[2] + '</font>');

			MGED.editProperty.call(this, ev);

			ev.stopPropagation();
		},

		operCallback = {
/*		
			editCSS : function (ev) {

				var $this = JlQ(this),
					elms = $this.text().match(/([^:\s*]+)\s*:\s*([^;}]*?)\s*;/);

				$this.data('rval', elms[2])
					.html('<span>'+elms[1]+'</span><font id="mg-elproperty-'+elms[1]+'" class="mg-changeable-input">'+ elms[2] + '</font>');

				MGED.editProperty.call(this, ev);
			},
*/
			deleteCSS : function (ev) {

				JlQ(this).remove();
			}
		},

		hoverHref = function (ev) {

			var $this = JlQ(this);

			if (ev.type == 'mouseover')	{
				if (!JlQ('input', $canvas).length) {
					JlQ('<div id="mg-add-href-rule" class="mg-elem-actions"></div>')
						.click(addRule)
						.appendTo($this);
				}
			}
			else {
				JlQ('#mg-add-href-rule').remove();
			}
		},

		hoverRule = function (ev) {

			var $this = JlQ(this),
				$parent = $this.parent();

			if (ev.type == 'mouseover')	{
				$parent.addClass('mg-csshover');
				//JlQ($this.children('span').text()).addClass('mg-cssrules-cursor');
				if (!JlQ('input', $canvas).length) {
					JlQ('<div id="mg-delete-element" class="mg-elem-actions mg-images mg-images-dark mg-images-overlay JLui-icon-trash"></div>')
						.click(deleteRule)
						.appendTo($this);
					JlQ('<div id="mg-add-csselement" class="mg-elem-actions mg-images mg-images-dark mg-images-overlay-second JLui-icon-plus"></div>')
						.click(addCSS)
						.appendTo($this);
				}
			}
			else {
				//JlQ('.mg-cssrules-cursor').removeClass('mg-cssrules-cursor');
				$parent.removeClass('mg-csshover');
				JlQ('#mg-delete-element, #mg-add-csselement').remove();
			}
		},
	
		hoverCSS = function (ev) {

			var $this = JlQ(this);

			if (ev.type == 'mouseover')	{
				$this.addClass('mg-csshover');
				if (!JlQ('input', $canvas).length) {
					JlQ('<div id="mg-delete-rule" class="mg-elem-actions mg-images mg-images-dark mg-images-overlay JLui-icon-trash"></div>')
						.click(deleteCSS)
						.appendTo($this);
				}
			}
			else {
				$this.removeClass('mg-csshover');
				JlQ('#mg-delete-rule').remove();
			}
		},
			
		removeRule = function (code) {

			var m = code.match(/.*\("([^"]*)"\),[^,]*,\s*(\d+)\)/);

			JlQ.rule.filterSheets(m[1]).deleteRule(m[2]);
		},
			
		operRule = function (oper, ev) {

			var /*isCSS = oper.search('CSS') != -1,*/
				$t = JlQ(this),
				$this = $t.parent('.mg-cssr, p').length ? $t : $t.parentsUntil('.mg-cssr').last(),
				$granpa = $this.parent().parent(),
				sel = $granpa.data('osel') || JlQ('span', $granpa).text(),
				sheet, ruleInd, ruleFilter, ruleSel, ind, ruleCSS, addCode, removeCode;

			if (curRule == 'All') {
				ruleInd = $granpa.prevAll('.mg-sheettxt').first().attr('sheetind');
				sheet = JlQ.rule.sheets()[ruleInd];
			}
			else {
				//ruleInd = curRule;
				sheet = curSheet;
			}
			ruleSel = JlQ.rule(sel, sheet);
			ind = getRuleInd($granpa, ruleSel);
			//ruleFilter = '.filter(function () {return this.href && this.href.search(/'+filterLocalPath(sheet.href).replace(/\//g, '\\/').replace(/\?.*$/, '')+'/) != -1})[0]';
			ruleFilter = filterLocalPath(sheet.href).replace(/\//g, '\\/').replace(/\?.*$/, '');

			that.selectedRule = ruleSel.eq(ind);
			that.selectedRuleInd = parseInt(JlQ('p', $granpa).attr('ruleind'));

			if (operCallback[oper]) {
				operCallback[oper].call($this.get(0), ev);
			}
			ruleCSS = MGUtils.text2SQString($granpa.text());
			addCode = "JlQ.rule('"+ruleCSS+"')"+'.appendTo(JlQ.rule.filterSheets("'+ruleFilter+'"), false, '+that.selectedRuleInd+')'
			removeCode = "JlQ.rule('"+sel+"', JlQ.rule.filterSheets(\""+ruleFilter+'")).eq('+ind+').remove()';

/*
			switch (oper) {
				case 'deleteRule':
					MGD.addTransform("remove()", 'delete-rule', removeCode, sel);
					break;
				case 'editCSS':
					MGD.addTransform("appendTo('"+ruleCSS+"')", 'edit-css-rule', removeCode + "; JlQ.rule('"+ruleCSS+"')"+'.appendTo(JlQ.rule.sheets()['+ruleInd+'], false, '+that.selectedRuleInd+')', sel);
					break;
				case 'deleteCSS':
					MGD.addTransform("appendTo('"+ruleCSS+"')", 'delete-css-rule', removeCode + "; JlQ.rule('"+ruleCSS+"')"+'.appendTo(JlQ.rule.sheets()['+ruleInd+'], false, '+that.selectedRuleInd+')', sel);
					break;
			}
*/
			if (oper == 'addRule') {
				MGD.addTransform("append('"+ruleCSS+"')", 'add-rule', addCode, sel);
			}
			else if (oper == 'deleteRule') {
				MGD.addTransform("remove()", 'delete-rule', removeCode, sel);
			}
			else if (ruleActionMap[oper]) {
				MGD.addTransform("append('"+ruleCSS+"')", ruleActionMap[oper], removeCode + "; " + addCode, sel);
			}
			if (curRule == 'All') {
				curRules = curSheet.cssRules();
			}			
			buildCSS();
		},
			
		buildCSS = function () {

			var res = '',
				filter = JlQ('#mg-sheet-filter').val().replace(/^\s*/, ''),
				prevSheet = '',
				i = -1;

			JlQ('#mg-waiting-css').show();

			JlQ.each(curRules, function () {

				var sel = this.selectorText,
					href = this.parentStyleSheet ? this.parentStyleSheet.href : '',
					txt;

				i++;

				if (!sel || filter && sel.search(filter) == -1 || sheetMap[href] == null) return true;

				if (prevSheet != href) {
					prevSheet = href || '';
					res += '<div class="mg-sheettxt" sheetind="'+sheetMap[prevSheet]+'">' + prevSheet.replace(/^https?:\/\//, '').replace(/\?.*$/, '') + '</div>';
					i = 0;
				}

				txt = this.cssText.substr(sel.length).replace('{', '{</p><div class="mg-cssr">').replace('}', lastCharRep).replace(/([a-z0-9_\-]+):([^;]*);/gi, '<div>$1:<font>$2;</font></div>');

				res += '<div class="mg-csstxt"><p ruleind="'+i+'"><span>' + sel + '</span>' + txt + '</div>';

			});

			if (!res) {
				res = '<div class="mg-css-message">No rules retrieved.</div>';
			}
			$canvas.html(res);

			JlQ('#mg-waiting-css').hide();
		};

	for (f, i = 0; f = ruleFuncs[i] ; i++) {
		eval('var '+ f + ' = function (ev) {that.operRule.call(this, "'+f+'", ev)};');
	}

	that.selectedRule = null;
	that.selectedRuleInd = null;


	that.restoreRule = function (action, code, rule, index) {

		var sheet;

		switch (action) {
			case 'delete-css-rule': case 'edit-css-rule':
				eval(code.replace(/(\.remove\(\)\s*;).*$/, '$1'));
				break;
			case 'edit-rule': case 'add-css-rule': case 'add-rule':
				removeRule(code);
				break;
		}
		sheet = eval(MGD.getJQueryRule(code));

		if (!sheet) sheet = curSheet;

		JlQ.rule(rule).appendTo(sheet, false, index);
	};

	that.renderCSS = function () {

		if (assignSheet()) {
			buildCSS();
		}
	};

	that.syncCSS = function () {

		if (CSSOutdated) {
			CSSOutdated = false;
			that.renderCSS();
		}
	};

	that.updateCSS = function () {

		if (JlQ('.mg-panel-domtree').hasClass('mg-hidden')) {
			CSSOutdated = true;
		}
		else {
			that.renderCSS();
		}
	};

	that.getRelPath = function () {

		var cssHref = JlQ('input', $canvas).closest('.mg-csstxt').prevAll('.mg-sheettxt').first().text();

		cssHref = filterLocalPath(cssHref);
		cssHref = cssHref.replace(/\/[^\/]+/g, '../').replace(/^[^\/]*((?:\.\.\/)*)[^\/]*$/, '$1');

		return cssHref;
	};

	that.assignRuleParams = function (code, ind) {

		var m = code.match(/(^.*?\.eq\((\d+)\))\.remove\(\)\s*;?/);

		if (m) {
			that.selectedRule = eval(m[1]);
		}
		that.selectedRuleInd = ind;
	};

	that.init = function () {

		propList = JlQ.objKeys(MGDefs.autoProps).sort();

		$canvas = JlQ('#mg-csscanv');

		if (JlQ.browser.msie && document.documentMode < 9) {
			$canvas.append('<div class="mg-css-message">CSS Editor not available from Internet Explorer 8.</div>');
			return;
		}
		
		if (JlQ.browser.opera) {
			lastCharRep = ';</div>}';
		}
		else {
			lastCharRep = '</div>}';
		}
		ruleProperty = JlQ.browser.msie ? 'rules' : 'cssRules';

		populateSelector();

		that.renderCSS();

		JlQ('#mg-cur-sheet').change(that.renderCSS);
		JlQ('#mg-sheet-filter').keypress(function () {setTimeout('MGCR.renderCSS();', 800)});

		JlQ('p', $canvas)
			.live('hover', hoverRule)
			.live('click', editRule);	
		JlQ('.mg-cssr > div:not(.mg-images)', $canvas)
			.live('hover', hoverCSS)
			.live('click', editCSS);
		JlQ('.mg-sheettxt', $canvas)
			.live('hover', hoverHref);
	};

	that.operRule = operRule;
	that.cancelRule = cancelRule;
};